﻿using System;
using System.Collections.Generic;
using System.IO;
using LingDong.IndexEntities.Dictionary;
using LingDong.IndexEntities.Helper;
using LingDong.SerializeProvider;

namespace LingDong.IndexReader
{
    internal class DictionaryIndex : IDisposable
    {
        #region Constructors

        internal DictionaryIndex()
        {
            LoadFromFile(
                IndexNameHelper.GetInvertedListFileName(), 
                IndexNameHelper.GetDictionaryFileName());
            CreateDicTermID();
        }

        /// <summary>
        /// Load dictionary index from index files
        /// </summary>
        /// <param name="invertedListFname"></param>
        /// <param name="dictionaryFname"></param>
        private void LoadFromFile(string invertedListFname, string dictionaryFname)
        {
            // deserialize dictionary offset
            using (FileStream fs = new FileStream(dictionaryFname, FileMode.Open))
            {
                termList = Serializer.Deserialize<Dictionary<string, DictionaryIndexEntity>>(fs);
            }

            // open dictionary index files
            invertedListStream = new FileStream(invertedListFname, FileMode.Open);
        }

        private void CreateDicTermID()
        {
            dicTermID = new Dictionary<int, string>();
            foreach (KeyValuePair<string, DictionaryIndexEntity> pair in termList)
            {
                dicTermID.Add(pair.Value.ID, pair.Key);
            }
        }

        #endregion


        #region Index Reader Methods

        internal int GetMaxTermID()
        {
            return termList.Count;
        }

        internal int GetTermID(string term)
        {
            if (!termList.ContainsKey(term))
                return -1;

            return termList[term].ID;
        }

        internal string GetTermByID(int id)
        {
            if (!dicTermID.ContainsKey(id))
                return null;

            return dicTermID[id];
        }

        internal int GetTermDocumentFrequency(string term)
        {
            if (!termList.ContainsKey(term))
                return 0;

            return termList[term].DF;
        }

        internal int GetTermFrequence(string term)
        {
            if (!termList.ContainsKey(term))
                return 0;

            return termList[term].TotalTF;
        }

        internal int GetTermFrequenceInTitle(string term)
        {
            if (!termList.ContainsKey(term))
                return 0;

            return termList[term].TotalTFInTitle;
        }

        internal PanGu.POS GetTermPOS(string term)
        {
            if (!termList.ContainsKey(term))
                return PanGu.POS.POS_UNK;

            return termList[term].TermPos;
        }

        internal PanGu.WordType GetTermType(string term)
        {
            if (!termList.ContainsKey(term))
                return PanGu.WordType.None;

            return termList[term].TermType;
        }

        internal Dictionary<int, InvertedListEntity> GetInvertedListByTerm(string term)
        {
            if (!termList.ContainsKey(term))
                return null;

            long offset = termList[term].InvertedListOffset;
            invertedListStream.Position = offset;
            return Serializer.Deserialize<Dictionary<int, InvertedListEntity>>(invertedListStream);
        }

        #endregion
        

        #region Private Members

        private FileStream invertedListStream;

        /// <summary>
        /// (term, term entity)
        /// </summary>
        private Dictionary<string, DictionaryIndexEntity> termList;

        /// <summary>
        /// (term id, term)
        /// </summary>
        private Dictionary<int, string> dicTermID;

        #endregion
        

        #region Disposable Related

        ~DictionaryIndex()
        {
            Dispose();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            // protect from being called multiple times.
            if (disposed)
            {
                return;
            }

            if (disposing)
            {
                // clean up all managed resources.
                if (invertedListStream != null)
                {
                    invertedListStream.Dispose();
                }
            }

            disposed = true;
        }

        private bool disposed = false;

        #endregion
    }
}
